using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Win32;
using System.IO;
using System.Reflection;
using System.Diagnostics;

namespace SAInterfaceLibrary
{
    /// <summary>
    /// Contains config info to help us run.
    /// </summary>
    public class Configuraiton
    {
        /// <summary>
        /// Determine if we are running in development mode or in install mode.
        /// </summary>
        public Configuraiton()
        {
            Trace.WriteLine("Configuration:: ctor");

            ///
            /// Configure the directories depending on development or production mode.
            /// This is probably dangerous, however, this is the easiest way to do it.
            /// And if the user wants to trick us into using a different set of templates,
            /// then they can. :-)
            /// 

            if (!IsDevelopmentMode())
            {
                Trace.WriteLine("Configuration:: In production mode");
                EventLogger.LogMessage("Running in production mode", System.Diagnostics.EventLogEntryType.Information, 1);

                using (RegistryKey our_config_info = GetOurRegKey())
                {
                    Trace.WriteLine("Configuration:: grabbing configuration paths");
                    _template_dir = (string)our_config_info.GetValue("TemplateDir");
                    Trace.WriteLine("Configuration:: template_dir " + _template_dir);
                    _unix_bin_path = (string)our_config_info.GetValue("LinuxBinDir");
                    Trace.WriteLine("Configuration:: _unix_bin_path " + _unix_bin_path);
                    _system_config_dir = (string)our_config_info.GetValue("SystemConfigDir");
                    Trace.WriteLine("Configuration:: _system_config_dir " + _system_config_dir);
                }
            }
            else
            {
                Trace.WriteLine("COnfiguration:: In development mode");
                EventLogger.LogMessage("Running in development mode", System.Diagnostics.EventLogEntryType.Information, 2);

                ///
                /// See if we can figure out where we are so we can access things like the linux dev tools
                /// 

                string assPath = Path.GetDirectoryName(Assembly.GetCallingAssembly().Location);
                assPath = assPath.Substring(0, assPath.IndexOf("ROOTBuildProjectCreatorSA"));
                assPath += @"WinBuildTools\bin";
                if (Directory.Exists(assPath))
                {
                    _unix_bin_path = assPath;
                }
            }

            ///
            /// Describe the versions of MSVC that
            /// we will support.
            /// 

            Trace.WriteLine("Configuration: Adding MSVC versions");
            _supported_msvc_versions.Add(new MSVCVersions.MSVC2010(_template_dir));
            _supported_msvc_versions.Add(new MSVCVersions.MSVC2008(_template_dir));
            _supported_msvc_versions.Add(new MSVCVersions.MSVC2005(_template_dir));
            _supported_msvc_versions.Add(new MSVCVersions.MSVC2003(_template_dir));

            ///
            /// Check to see who is the one we should support by default.
            /// 

            _default_msvc_version = _supported_msvc_versions[0];
            foreach (ConfigMSVCVersionInfo cf in _supported_msvc_versions)
            {
                Trace.WriteLine("Configuration: Check to see if " + cf.Name + " is on the machine");
                if (cf.IsOnMachine)
                {
                    _default_msvc_version = cf;
                    break;
                }
            }

        }

        /// <summary>
        /// Try to determine if we are running in development mode... or not.
        /// </summary>
        /// <returns></returns>
        private bool IsDevelopmentMode()
        {

            ///
            /// If there is no registry entries, then we are definately in development mode
            /// 

            string template_dir = null;
            using (RegistryKey our_config_info = GetOurRegKey())
            {

                if (our_config_info == null)
                {
                    EventLogger.LogMessage("Development mode because there are no registry keys", System.Diagnostics.EventLogEntryType.Information, 3);
                    return true;
                }

                template_dir = (string) our_config_info.GetValue("TemplateDir");
            }

            ///
            /// Now, see if the templates are right here. If they are we will assume we are
            /// in development mode. Unless it turns out that the template directory happens to
            /// be the installed directory.
            /// 

            DirectoryInfo template_dir_info = new DirectoryInfo(_template_dir);
            if (template_dir_info.Exists)
            {
                if (template_dir != template_dir_info.FullName)
                {
                    ///
                    /// Finally, look for one of the files we know should be there
                    /// Turns out that on XP one can have a default startup directory
                    /// that has a Templates subdirectory. Yikes!
                    /// 

                    if (File.Exists(template_dir_info.FullName + "\\build_me.bat"))
                    {
                        EventLogger.LogMessage("Development mode because we found a local template directory with build_me.bat in it: " + template_dir_info.FullName, System.Diagnostics.EventLogEntryType.Information, 4);
                        return true;
                    }
                }
            }

            ///
            /// Ok -- the installed info exists, and there is nothign where we are running -- so
            /// we can assume that this is the right place.
            /// 

            return false;
        }

        /// <summary>
        /// Returns the Registry key for our store of info.
        /// </summary>
        /// <returns></returns>
        private RegistryKey GetOurRegKey()
        {
            using (RegistryKey k = Registry.LocalMachine.OpenSubKey("SOFTWARE"))
            {
                try
                {
                    return k.OpenSubKey("ROOT Builder");
                }
                catch
                {
                }
                return null;
            }
        }

        /// <summary>
        /// Left to our own devicves, what would we guess the user wanted?
        /// </summary>
        private ConfigMSVCVersionInfo _default_msvc_version = null;

        /// <summary>
        /// The version that we are using to do the builds.
        /// </summary>
        private ConfigMSVCVersionInfo _msvc_config = null;

        /// <summary>
        /// What is the default MSVC version we will build for?
        /// </summary>
        public string DefaultMSVCVersion
        {
            get { return _default_msvc_version.Name; }
        }

        private List<ConfigMSVCVersionInfo> _supported_msvc_versions = new List<ConfigMSVCVersionInfo>();

        /// <summary>
        /// Return a list of names of supported versions.
        /// </summary>
        public string[] MSVCVersionsSupported
        {
            get
            {
                string[] result = new string[_supported_msvc_versions.Count];
                int index = 0;
                foreach (ConfigMSVCVersionInfo cf in _supported_msvc_versions)
                {
                    result[index] = cf.Name;
                    index = index + 1;
                }
                return result;
            }
        }

        /// <summary>
        /// Holds the default template directory.
        /// </summary>
        private string _template_dir = "Templates\\";

        /// <summary>
        /// Gets the full directory for a template
        /// </summary>
        public string ProjectTempmlatePath
        {
            get { return _msvc_config.ProjectTempmlatePath; }
        }

        private string _build_bat_template = @"build_me.bat";

        /// <summary>
        /// Gets teh template for teh build bat file
        /// </summary>
        public string BuildBATTemplatePath
        {
            get { return _template_dir + _build_bat_template; }
        }

        private string _rebuild_bat_template = @"rebuild_me.bat";

        public string RebuildBATTemplatePath
        {
            get { return _template_dir + _rebuild_bat_template; }
        }

        private string _clean_bat_template = @"clean_me.bat";

        public string CleanBATTemplatePath
        {
            get { return _template_dir + _clean_bat_template; }
        }

        private string _config_bat_template = @"configure_cmd.bat";

        public string ConfigBATTemplatePath
        {
            get { return _template_dir + _config_bat_template; }
        }

        private string _setup_config_template = @"setup_config.sh";

        public string SetupConfigSHTemplatePath
        {
            get { return _template_dir + _setup_config_template; }
        }

        private string _vc_project_settings_template = "vc_project_settings_template.vcproj.user";

        /// <summary>
        /// Returns the location of the project settings template.
        /// </summary>
        public string VCProjectSettingsTemplatePath
        {
            get { return _template_dir + _vc_project_settings_template; }
        }

        /// <summary>
        /// Returns the install dir for the IDE -- devenv should be in here.
        /// </summary>
        public string IDEInstallDir
        {
            get { return _msvc_config.InstallDir; }
        }

        private static Configuraiton _instance = null;

        /// <summary>
        /// The singleton instance for config info
        /// </summary>
        public static Configuraiton Instance
        {
            get {
                if (_instance == null)
                {
                    _instance = new Configuraiton();
                }
                return _instance;
            }
        }

        private string _subdir_for_ide = ".";

        /// <summary>
        /// Subdirectory where the IDE files should go.
        /// </summary>
        public string SubdirectoryForIDE
        {
            get { return _subdir_for_ide; }
        }

        private string _subdir_for_scripts = "vside";

        /// <summary>
        /// Subdirectory to use to store script files.
        /// </summary>
        public string SubdirectoryForScripts
        {
            get { return _subdir_for_scripts; }
        }



        /// <summary>
        /// Some directories we should not bother translating...
        /// </summary>
        /// <param name="subdir"></param>
        /// <returns></returns>
        internal bool DirectoryIsGood(System.IO.DirectoryInfo subdir)
        {
            if (subdir.Name == ".svn")
            {
                return false;
            }
            if (subdir.Name == SubdirectoryForIDE)
            {
                return false;
            }
            return true;
        }

        private string _unix_bin_path = @"C:\users\gwatts\Documents\Visual Studio 2008\Projects\Root Builder Tools\WinBuildTools\bin";

        public string UnixBinPath
        {
            get { return _unix_bin_path; }
            set { _unix_bin_path = value; }
        }


        /// <summary>
        /// Is this the type of file we want to include in this project? We automatically include
        /// everything that is under SVN control. Nothing else is done. We will explicitly NOT
        /// support cvs by this move.
        /// </summary>
        /// <param name="finfo"></param>
        /// <returns></returns>
        internal bool FileIsGood(System.IO.FileInfo finfo)
        {
            ///
            /// If this is one of the vside files, then we will allow it. This makes it easy to
            /// edit the ide files.

            if (finfo.DirectoryName.Contains("vside"))
            {
                return true;
            }

            ///
            /// Create the SVN follow-on file.
            /// 

            string svn_filename = finfo.DirectoryName + @"\.svn\text-base\" + finfo.Name + ".svn-base";

            ///
            /// If it exists, we allow it.
            /// 

            if (!File.Exists(svn_filename))
            {
                return false;
            }

            ///
            /// Make sure the config says it is ok.
            /// 

            return _msvc_config.FileIsGood(finfo);
        }

        /// <summary>
        /// The default config that we will build with if no one else tells us what to do.
        /// </summary>
        public string DefaultConfigName
        {
            get { return "Release"; }
        }

        /// <summary>
        /// If we are in development mode, or normal mode, it should be the same...
        /// </summary>
        private string _user_config_dir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + @"\ROOT Builder\Build Configs";

        /// <summary>
        /// Default place they are if we are running in development mode.
        /// </summary>
        private string _system_config_dir = ".\\Configs";

        /// <summary>
        /// Where build configs are located for the user.
        /// </summary>
        public string UserConfigDirectory
        {
            get
            {
                return _user_config_dir;
            }
        }

        /// <summary>
        /// Where build config templates are located for the system/install.
        /// </summary>
        public string SystemConfigDirectory
        {
            get
            {
                return _system_config_dir;
            }
        }

        /// <summary>
        /// User wants us to use a paricular version of msvc to do the generation.
        /// </summary>
        /// <param name="p"></param>
        public void SetMSVCVersion(string p)
        {
            ///
            /// Make sure we can find the version in here!
            /// 

            foreach (ConfigMSVCVersionInfo cf in _supported_msvc_versions)
            {
                if (cf.Name == p)
                {
                    _msvc_config = cf;
                    return;
                }
            }
            throw new ArgumentException("MSVC version '" + p + "' is not supported");
        }

        /// <summary>
        /// Returns if the config requires a user settings file or not.
        /// </summary>
        public bool UsesSettingsFile
        {
            get
            {
                return _msvc_config.UsesSettingsFile;
            }
        }

        /// <summary>
        /// Allows you to move through all the various things we might want to
        /// push out.
        /// </summary>
        public List<SAInterfaceLibrary.ConfigMSVCVersionInfo.FileTransInfo> FilesToTranslate
        {
            get
            {
                return _msvc_config.FilesToTranslate;
            }
        }

        /// <summary>
        /// See if the config knows how to do the translation
        /// </summary>
        /// <param name="input_string"></param>
        /// <returns></returns>
        internal string TranslateMacro(string input_string)
        {
            return _msvc_config.TranslateMacro(input_string);
        }
    }
}
